using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using HunterPluginSDK;
using HunterPluginSDK.Interface;
using HunterPluginSDK;
using HunterPluginSDK.Interface;


namespace Engine.IO
{
    /// <summary>
    /// Component to watch changes done in CSV file directory
    /// </summary>
    public class CsvFileWatcher
    {
        private Dictionary<FileSystemWatcher, DataSchema.Settings.SettingSchema.MyCollectionRow> _watchers;
        private Dictionary<string, CollectionCacheItem> _collCache;
        private System.ComponentModel.BackgroundWorker _cacheCleaner;

        private IProgressHandler _logger;
        private CsvFileWatcher()
        {
        }

        static private CsvFileWatcher _Instance;
        static public CsvFileWatcher Instance
        {
            get 
            {
                if (_Instance == null)
                {
                    _Instance = new CsvFileWatcher();
                }
                return _Instance; 
            }
        }

        #region PUBLIC INTERFACE
        /// <summary>
        /// Function to initialize CSV files watcher
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="ph"></param>
        public void InitWatcher(DataSchema.Settings.SettingSchema.MyCollectionDataTable dt, IProgressHandler ph)
        {
            Init(ph);
            int count = 0;
            foreach(DataSchema.Settings.SettingSchema.MyCollectionRow r in dt.Rows)
            {
                if (r.IsWatchFolderNull() == false && r.IsIsWatcherActiveNull() == false && r.IsWatcherActive)
                {
                    DirectoryInfo di = new DirectoryInfo(r.WatchFolder);
                    if (di.Exists)
                    {
                        System.IO.FileSystemWatcher w = new System.IO.FileSystemWatcher();
                        w.Path = r.WatchFolder;
                        w.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                           | NotifyFilters.FileName | NotifyFilters.DirectoryName;
                        w.EnableRaisingEvents = true;
                        w.Filter = Engine.CSV.CsvHuntInfo.CSVFILTER;
                        w.Created += new FileSystemEventHandler(w_Changed);
                        _watchers.Add(w, r);
                        count++;
                    }
                    else
                        this._logger.WriteToOutput("Watcher Error. Directory not found " + r.WatchFolder, LogPriority.ERROR);
                }
            }
            if (count > 0)
                this._logger.WatcherDescription = count + " watchers";
        }
        
        /// <summary>
        /// Function to deactivate Watcher and save all collection from cache
        /// </summary>
        public void CloseWatcher()
        {
            this._cacheCleaner.CancelAsync();
            foreach (string s in this._collCache.Keys)
            {
                _collCache[s].MyCollection.WriteXml(s);
            }
            this._collCache.Clear();
            this._watchers.Clear();
        }
        #endregion

        #region EVENTS
        void w_Changed(object sender, FileSystemEventArgs e)
        {
            DataSchema.Settings.SettingSchema.MyCollectionRow r = _watchers[(FileSystemWatcher)sender];
            _logger.WriteToOutput("Watcher. New File " + e.Name + " copied to " + r.WatchFolder, LogPriority.INFO);
            try
            {
                DataSchema.CollectionSchema coll = null;
                lock (_collCache)
                {
                    if (_collCache.ContainsKey(r.Path))
                    {
                        coll = _collCache[r.Path].MyCollection;
                        _logger.WriteToOutput("Watcher. " + r.Path + " read from cache", LogPriority.INFO);
                    }
                    else
                    {
                        coll = new DataSchema.CollectionSchema();
                        coll.ReadXml(r.Path);
                        _collCache[r.Path] = new CollectionCacheItem(coll);
                        _logger.WriteToOutput("Watcher. " + r.Path + " saved to cache", LogPriority.INFO);
                    }
                }

                coll.AcceptChanges();

                Engine.Factory.CollectionFactory factory = Engine.Factory.CollectionFactory.OpenCollection(coll, _logger);
                factory.CreateNewCollectionEntity(e.Name);

                //coll.WriteXml(r.Path);
                coll.AcceptChanges();
                //_logger.WriteToOutput("Watcher. Collection " + r.Path + " was saved", LogPriority.INFO);

            }
            catch (Exception ex)
            {
                _logger.WriteToOutput("Watcher. Error while processing " + e.Name + " copied to " + r.WatchFolder + " " + ex.ToString(), LogPriority.ERROR); 
            }
        }
        #endregion

        #region PRIVATE
        private void Init(IProgressHandler ph)
        {
            _watchers = new Dictionary<FileSystemWatcher, DataSchema.Settings.SettingSchema.MyCollectionRow>();
            _collCache = new Dictionary<string, CollectionCacheItem>();
            _cacheCleaner = new System.ComponentModel.BackgroundWorker();
            _cacheCleaner.WorkerSupportsCancellation = true;
            _cacheCleaner.DoWork+=new System.ComponentModel.DoWorkEventHandler(_cacheCleaner_DoWork);
            _cacheCleaner.RunWorkerAsync();
            _logger = ph;
        }

        void _cacheCleaner_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            while (_cacheCleaner.CancellationPending == false)
            {
                lock (_collCache)
                {
                    List<string> ls = new List<string>();
                    foreach (string s in this._collCache.Keys)
                    {
                        if (_collCache[s].NotUsed)
                        {
                            _collCache[s].MyCollection.WriteXml(s);
                            _logger.WriteToOutput("Watcher. Collection " + s + " was saved", LogPriority.INFO);
                            ls.Add(s);
                        }
                    }
                    foreach (string s in ls)
                    {
                        _collCache.Remove(s);
                        _logger.WriteToOutput("Watcher. " + s + " removed from cache", LogPriority.INFO);
                    }
                }
                System.Threading.Thread.Sleep(10000);
            }
        }
        #endregion
    }

    class CollectionCacheItem
    {
        public CollectionCacheItem (DataSchema.CollectionSchema coll)
        {
            _myCollection = coll;
            _cachedat = DateTime.Now;
        }

        private DateTime _cachedat;
        private DataSchema.CollectionSchema _myCollection;
        public DataSchema.CollectionSchema MyCollection
        {
            get {
                _cachedat = DateTime.Now;
                return _myCollection; 
            }
        }

        public bool NotUsed
        {
            get {
                TimeSpan ts = DateTime.Now - _cachedat;
                if (ts.TotalSeconds > 60)
                    return true;
                return false;
            }
        }
	
	
    }
}
